package com.societyGames.action
{
import com.societyGames.system.EventObject;

import flash.events.Event;
import flash.events.EventDispatcher;

public class ActionQueue extends EventDispatcher
{
  private var _queue:Vector.<IAction> = new Vector.<IAction>();
  private var _currentAction:IMultipleFrameAction;
  private var _maximumCount:uint = uint.MAX_VALUE;
  private var _emptyEventObject:EventObject;

  public function ActionQueue()
  {
    _emptyEventObject = new EventObject(this, "EMPTY");
  }

  public function get isEmpty():Boolean
  {
    return _currentAction == null && _queue.length == 0;
  }

  public function get emptyEventObject():EventObject
  {
    return this._emptyEventObject;
  }

  public function set maximumCount(value:uint):void
  {
    _maximumCount = value;
  }

  public function add(action:IAction):void
  {
    if (this._queue.length >= _maximumCount)
    {
      throw new ActionQueueLimitError("ActionQueue exceeded maximum action count of " + _maximumCount);
    }

    //If we're not waiting for an action to complete
    if (_currentAction == null)
    {
      doAction(action); //Just do it.
    }
    else //Store it for later.
    {
      this._queue.push(action);
    }
  }

  public function stop():void
  {
    if (this._currentAction != null)
    {
      this._currentAction.completeEventObject.removeEventListener(currentActionCompleteHandler);
      var stoppable:IStoppable = this._currentAction as IStoppable;
      if (stoppable != null)
      {
        stoppable.stop();
      }
      this._currentAction = null;
    }
    this._queue.length = 0; //Clear out remaining commands.
  }

  //Performs an action and moves to the next when needed.
  private function doAction(action:IAction):void
  {
    this._currentAction = action as IMultipleFrameAction;
    if (this._currentAction == null)
    {
      action.startAction();
      tryDoNextAction(); //If we have no actions left to do.
    }
    else
    {
      this._currentAction.completeEventObject.addEventListener(currentActionCompleteHandler);
      this._currentAction.startAction();
    }
  }

  //When a multi-frame action completes.
  private function currentActionCompleteHandler(event:Event):void
  {
    this._currentAction.completeEventObject.removeEventListener(currentActionCompleteHandler);
    this._currentAction = null;
    tryDoNextAction();
  }

  //Try to do the next one if we can otherwise raise event if empty
  private function tryDoNextAction():void
  {
    if (this._queue.length > 0)
    {
      doAction(this._queue.shift());
    }
    else
    {
      this._emptyEventObject.dispatchEvent(); //we're empty!
    }
  }
}
}